package org.wu.framework.lazy.orm.database.sql.expand.database.persistence.proxy;


import lombok.extern.slf4j.Slf4j;
import org.wu.framework.core.annotation.AnnotatedElementUtils;
import org.wu.framework.lazy.database.datasource.proxy.connection.LazyProxyConnection;
import org.wu.framework.lazy.orm.core.stereotype.proxy.ProxyLazyBaseLayerStrategicApproach;
import org.wu.framework.lazy.orm.database.lambda.LazyBaseDDLOperation;
import org.wu.framework.lazy.orm.database.lambda.dynamic.LazyDynamicDatasourceAdapter;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.LazyOperationMethod;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.ddl.LazyDDLOperationMethod;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : Jia wei Wu
 * @version 1.0
 * describe : DDL 操作代理对象
 * @date : 2020/6/25 下午11:19
 * @see LazyBaseDDLOperation
 */
@Slf4j
public class LazyDDLOperationProxy extends AbstractLazyOperationProxyInvocationHandler implements InvocationHandler {

    protected final ConcurrentHashMap<String, LazyOperationMethod> LAZY_OPERATION_DDL_METHOD_MAP = new ConcurrentHashMap<>();

    private final List<LazyDDLOperationMethod> lazyDDLOperationMethodList;

    private final LazyDynamicDatasourceAdapter lazyDynamicDatasourceAdapter;


    public LazyDDLOperationProxy(List<LazyDDLOperationMethod> lazyDDLOperationMethodList, LazyDynamicDatasourceAdapter lazyDynamicDatasourceAdapter) {
        this.lazyDDLOperationMethodList = lazyDDLOperationMethodList;
        this.lazyDynamicDatasourceAdapter = lazyDynamicDatasourceAdapter;
    }

    /**
     * @param proxy     代理对象
     * @param method    代理方法
     * @param args      代理方法参数
     * @param retryTime 重试
     * @param throwable 异常
     * @param hasRetry  是否已经重试
     * @return 返回的执行结果
     */
    @Override
    public Object doRetryInvoke(Object proxy, Method method, Object[] args, int retryTime, Throwable throwable, boolean hasRetry) throws Throwable {

        ProxyLazyBaseLayerStrategicApproach mergedAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, ProxyLazyBaseLayerStrategicApproach.class);
        if (null != mergedAnnotation) {
            LazyOperationMethod lazyOperationMethod = getLazyOperationMethod(mergedAnnotation.proxyClassName());
            if (null == lazyOperationMethod) {
                log.error("无法找到对应class ：【{}】的代理实现", mergedAnnotation.proxyClassName());
            }
            return doInvoke(lazyOperationMethod, args);
        } else {
            return method.invoke(this, args);
        }
    }


    /**
     * 获取不同的策略
     *
     * @param proxyClassName class 名称
     * @return 策略
     */
    public LazyOperationMethod getLazyOperationMethod(String proxyClassName) {
        if (LAZY_OPERATION_DDL_METHOD_MAP.isEmpty()) {
            lazyDDLOperationMethodList.forEach(lazyOperationMethod -> LAZY_OPERATION_DDL_METHOD_MAP.put(lazyOperationMethod.getClass().getName(), lazyOperationMethod));
        }

        return LAZY_OPERATION_DDL_METHOD_MAP.get(proxyClassName);
    }


    /**
     * 获取当前连接
     *
     * @return 数据当前连接
     */
    @Override
    LazyProxyConnection determineConnection() throws SQLException {
        return lazyDynamicDatasourceAdapter.determineConnection();
    }
}
